from setuptools import setup, find_packages, Extension
from setuptools.command.build_ext import build_ext
import os
import sys
import subprocess
import platform

# 增强的调试输出函数 / Enhanced debug output function
def debug_print(msg):
    """强制显示调试信息 / Force display debug information"""
    import datetime
    timestamp = datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3]
    print(f"[SETUP {timestamp}] {msg}")
    sys.stdout.flush()  # 强制刷新缓冲区 / Force flush buffer

# 开始执行标识 / Start execution marker
debug_print("=== setup.py execution started ===")
debug_print(f"Python version: {sys.version}")
debug_print(f"Current working directory: {os.getcwd()}")
debug_print(f"Command line arguments: {sys.argv}")
debug_print(f"Called module: {__name__}")
debug_print(f"Script file (__file__): {__file__ if '__file__' in globals() else 'Not available'}")
debug_print(f"Is main script: {__name__ == '__main__'}")
debug_print(f"locals: {list(locals().keys())}")
debug_print(f"globals: {list(globals().keys())}")
debug_print(f"globals() is locals(): {globals() is locals()}")
debug_print(f"id(globals()): {id(globals())}")
debug_print(f"id(locals()): {id(locals())}")

# 创建 locals() 的副本以避免遍历时修改字典大小
locals_copy = dict(locals())
for k, v in locals_copy.items():
    debug_print(f">>>> k: {k}")
    # if k == 'code':
    #     debug_print(f"code: {v}")
    if type(v) == str and k != 'code':
        debug_print(f"{k}: {v}")
    elif type(v) == int:
        debug_print(f"{k}: {v}")
    elif type(v) == float:
        debug_print(f"{k}: {v}")
    elif type(v) == bool:
        debug_print(f"{k}: {v}")
    else:
        debug_print(f"{k}: {type(v)}")

# 显示调用栈 / Show call stack
import traceback
debug_print("=== Call Stack ===")
for line in traceback.format_stack()[:-1]:
    debug_print(line.strip())

class CMakeExtension(Extension):
    def __init__(self, name, sourcedir=''):
        print("*" * 16)
        print(f"Creating CMakeExtension for {name}")
        Extension.__init__(self, name, sources=[])
        self.sourcedir = os.path.abspath(sourcedir)

class CMakeBuild(build_ext):
    def run(self):
        print("Starting CMakeBuild.run()")
        try:
            out = subprocess.check_output(['cmake', '--version'])
            print(f"Found CMake: {out.decode().strip()}")
        except OSError:
            raise RuntimeError("CMake must be installed to build the extension")

        for ext in self.extensions:
            self.build_extension(ext)

    def build_extension(self, ext):
        print(f"Building extension: {ext.name}")
        extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
        print(f"Extension directory: {extdir}")
        
        cmake_args = [
            f'-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}',
            f'-DPYTHON_EXECUTABLE={sys.executable}'
        ]

        # 设置构建类型 / Set build type
        cfg = 'Debug' if self.debug else 'Release'
        build_args = ['--config', cfg]

        # 设置平台特定的参数 / Set platform-specific parameters
        if platform.system() == "Windows":
            cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)]
            if sys.maxsize > 2**32:
                cmake_args += ['-A', 'x64']
            build_args += ['--', '/m']
        else:
            cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg]
            build_args += ['--', '-j2']

        # 创建构建目录 / Create build directory
        build_temp = os.path.join(self.build_temp, ext.name)
        if not os.path.exists(build_temp):
            os.makedirs(build_temp)
        print(f"Build directory: {build_temp}")

        # 运行 CMake / Run CMake
        print(f"Running CMake in {build_temp}")
        print(f"CMake arguments: {cmake_args}")
        subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=build_temp)
        print(f"Building with arguments: {build_args}")
        subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=build_temp)

        # 检查输出文件 / Check output files
        if platform.system() == "Windows":
            ext_file = os.path.join(extdir, "my_c_string.pyd")
            # 在 Windows 下，也检查可能的 DLL 文件位置 / On Windows, also check possible DLL file locations
            possible_files = [
                # os.path.join(extdir, "my_c_string.pyd"),
                os.path.join(build_temp, "Release", "my_c_string.pyd"),
                os.path.join(build_temp, "Release", "my_c_string.dll"),
                os.path.join(build_temp, "my_c_string.pyd"),
                os.path.join(build_temp, "my_c_string.dll")
            ]
        else:
            ext_file = os.path.join(extdir, "my_c_string.so")
            possible_files = [ext_file]
        
        print(f"Looking for extension file at: {ext_file}")
        
        # 检查所有可能的位置 / Check all possible locations
        found_file = None
        for possible_file in possible_files:
            print(f"Checking: {possible_file}")
            if os.path.exists(possible_file):
                found_file = possible_file
                print(f"Found extension file at: {found_file}")
                break
        
        if found_file:
            # 检查是否需要复制文件 / Check if file copy is needed
            need_copy = False
            
            if found_file != ext_file:
                # 文件位置不同，需要复制 / Files are in different locations, need to copy
                need_copy = True
                print(f"Files are in different locations")
            elif os.path.exists(ext_file):
                # 文件位置相同，但检查内容是否不同 / Files are in same location, but check if content is different
                import filecmp
                import hashlib
                
                # 计算文件hash值的函数 / Function to calculate file hash
                def calculate_file_hash(filepath):
                    hash_md5 = hashlib.md5()
                    try:
                        with open(filepath, "rb") as f:
                            for chunk in iter(lambda: f.read(4096), b""):
                                hash_md5.update(chunk)
                        return hash_md5.hexdigest()
                    except Exception as e:
                        return f"Error: {e}"
                
                # 打印文件信息和hash值 / Print file information and hash values
                found_hash = calculate_file_hash(found_file)
                ext_hash = calculate_file_hash(ext_file)
                
                print(f"Source file: {os.path.abspath(found_file)}")
                print(f"Source hash: {found_hash}")
                print(f"Target file: {os.path.abspath(ext_file)}")
                print(f"Target hash: {ext_hash}")
                
                if not filecmp.cmp(found_file, ext_file, shallow=False):
                    need_copy = True
                    print(f"Files have different content (hash mismatch)")
                else:
                    print(f"Files are identical, no need to copy")
            else:
                # 目标文件不存在，需要复制 / Target file does not exist, need to copy
                need_copy = True
                print(f"Target file does not exist")
            
            if need_copy:
                import shutil
                print(f"Copying {found_file} to {ext_file}")
                os.makedirs(os.path.dirname(ext_file), exist_ok=True)
                shutil.copy2(found_file, ext_file)
                print(f"Successfully copied extension to: {ext_file}")
            else:
                print(f"Extension already up-to-date at: {ext_file}")
        else:
            print(f"Warning: Extension file not found in any expected location")
            print(f"Build temp directory contents:")
            for root, dirs, files in os.walk(build_temp):
                for file in files:
                    if 'my_c_string' in file:
                        print(f"  Found: {os.path.join(root, file)}")

# 检查是否存在 pyproject.toml / Check if pyproject.toml exists
def has_pyproject_toml():
    return os.path.exists('pyproject.toml')

def get_version():
    """从 my_package/__init__.py 获取版本信息 / Get version information from my_package/__init__.py"""
    version_dict = {}
    try:
        with open('my_package/__init__.py', 'r', encoding='utf-8') as f:
            exec(f.read(), version_dict)
        return version_dict.get('__version__', '0.1')
    except Exception:
        return '0.1'

print("+" * 16)
debug_print("About to execute assert False to verify code execution")
# assert False  # 用户的调试断点 / User's debug breakpoint

# 根据是否存在 pyproject.toml 来决定配置方式 / Decide configuration method based on pyproject.toml existence
if has_pyproject_toml():
    print("Found pyproject.toml - using minimal setup.py configuration")
    # 当存在 pyproject.toml 时，只需要配置 C 扩展 / When pyproject.toml exists, only configure C extensions
    setup(
        ext_modules=[CMakeExtension('my_package.c_module.my_c_string', 'my_package/c_module')],
        cmdclass=dict(build_ext=CMakeBuild),
    )
else:
    print("No pyproject.toml found - using full setup.py configuration")
    # 后备方案：完整的 setup.py 配置 / Fallback: full setup.py configuration
    setup(
        name='my_package',
        version=get_version(),
        description='A sample Python package with C extension',
        author='Your Name',
        author_email='your.email@example.com',
        packages=find_packages(),
        ext_modules=[CMakeExtension('my_package.c_module.my_c_string', 'my_package/c_module')],
        cmdclass=dict(build_ext=CMakeBuild),
        python_requires='>=3.6',
        classifiers=[
            'Development Status :: 3 - Alpha',
            'Intended Audience :: Developers',
            'License :: OSI Approved :: MIT License',
            'Programming Language :: Python :: 3',
            'Programming Language :: C',
        ],
        install_requires=[],
        extras_require={
            'dev': [
                'pytest>=6.0',
                'pytest-cov',
                'black',
                'flake8',
                'mypy',
            ],
            'test': [
                'pytest>=6.0',
                'pytest-cov',
            ],
        },
    )


# xxx
